using NFreeMarker.Template;

namespace NFreeMarker.Core
{
    /**
     * A class that represents a Range between two integers.
     */

    internal sealed class Range : Expression
    {
        internal readonly Expression Left;
        internal readonly Expression Right;

        internal Range(Expression left, Expression right)
        {
            Left = left;
            Right = right;
        }

        internal bool HasRhs()
        {
            return Right != null;
        }

        protected override ITemplateModel _getAsTemplateModel(Environment env)
        {
            int min = EvaluationUtil.GetNumber(Left, env).IntValue();
            if (Right != null)
            {
                int max = EvaluationUtil.GetNumber(Right, env).IntValue();
                return new NumericalRange(min, max);
            }
            return new NumericalRange(min);
        }

        internal override bool IsTrue(Environment env)
        {
            string msg = "Error " + GetStartLocation() + ". "
                         + "\nExpecting a boolean here."
                         + " Expression " + this + " is a range.";
            throw new NonBooleanException(msg, env);
        }

        public override string GetCanonicalForm()
        {
            string rhs = Right != null ? Right.GetCanonicalForm() : "";
            return Left.GetCanonicalForm() + ".." + rhs;
        }

        internal override bool IsLiteral()
        {
            bool rightIsLiteral = Right == null || Right.IsLiteral();
            return ConstantValue != null || (Left.IsLiteral() && rightIsLiteral);
        }

        protected override Expression DeepCloneImpl(string name, Expression subst)
        {
            return new Range(Left.DeepClone(name, subst), Right.DeepClone(name, subst));
        }
    }
}